﻿using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;

namespace Away.Common.Mvc.Auth;

public struct JwtClaimNames
{
    public const string Aud = JwtRegisteredClaimNames.Aud;
    public const string Iss = JwtRegisteredClaimNames.Iss;
    public const string AuthTime = JwtRegisteredClaimNames.AuthTime;
    public const string Uid = "uid";
}

/// <summary>
/// 构建令牌
/// </summary>
public interface IJwtTokenBuilder
{
    TokenResult Bulder(params Claim[] claims);
    TokenResult Bulder(int uid);
}

[ServiceInject(ServiceLifetime.Scoped)]
public class JwtTokenBuilder : IJwtTokenBuilder
{
    private readonly IConfiguration configuration;
    private JwtSettings Options => configuration.GetSection("JwtSettings").Get<JwtSettings>()!;

    public JwtTokenBuilder(IConfiguration configuration)
    {
        this.configuration = configuration;
    }

    public TokenResult Bulder(int uid)
    {
        return Bulder(new Claim(JwtClaimNames.Uid, Convert.ToString(uid)));
    }

    public TokenResult Bulder(params Claim[] claims)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var authTime = DateTime.UtcNow;
        var expiresAt = authTime.AddHours(Options.Expires);

        List<Claim> claimList = new()
        {
            new Claim(JwtClaimNames.Aud, Options.Audience),
            new Claim(JwtClaimNames.Iss, Options.Issuer),
            new Claim(JwtClaimNames.AuthTime, $"{new DateTimeOffset(authTime).ToUnixTimeSeconds()}"),
        };
        claimList.AddRange(claims);

        var subject = new ClaimsIdentity(claimList);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = subject,
            Expires = expiresAt,
            SigningCredentials = new SigningCredentials(Options.SigningKey, SecurityAlgorithms.HmacSha256Signature)
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        var tokenString = tokenHandler.WriteToken(token);

        return new TokenResult
        {
            Access_token = tokenString,
            Token_type = JwtBearerDefaults.AuthenticationScheme,
            Expires = new DateTimeOffset(expiresAt).ToUnixTimeSeconds()
        };
    }
}

public class TokenResult
{
    private string access_token = string.Empty;
    private string token_type = string.Empty;

    public string Access_token { get => access_token ?? string.Empty; set => access_token = value; }
    public string Token_type { get => token_type ?? string.Empty; set => token_type = value; }

    /// <summary>
    /// 有效期 UnixTime
    /// </summary>
    public long Expires { get; set; }
}